import {
  BoxGeometry,
  Camera,
  Mesh,
  MeshBasicMaterial,
  Object3D,
  Vector3,
} from 'three'
import { ref, shallowRef } from 'vue'

const gizmoMaterial = new MeshBasicMaterial({
  depthTest: false,
  depthWrite: false,
  fog: false,
  toneMapped: false,
  transparent: true,
})
const matRed = gizmoMaterial.clone()
matRed.color.setHex(0xff0000)

const matGreen = gizmoMaterial.clone()
matGreen.color.setHex(0x00ff00)

const matBlue = gizmoMaterial.clone()
matBlue.color.setHex(0x0000ff)

export function useTransform() {
  const catchCamera = shallowRef<Camera | null>(null)
  const catchElement = ref<HTMLElement | null>(null)
  const root = shallowRef(new Object3D())
  const object = shallowRef<Object3D | null>(null)
  const handlers = ref({
    X: [
      {
        x: 1,
        y: 0,
        z: 0,
      },
      {
        x: -1,
        y: 0,
        z: 0,
      },
    ],
    Y: [
      {
        x: 0,
        y: 1,
        z: 0,
      },
      {
        x: 0,
        y: -1,
        z: 0,
      },
    ],
    Z: [
      {
        x: 0,
        y: 0,
        z: 1,
      },
      {
        x: 0,
        y: 0,
        z: -1,
      },
    ],
  })
  const handlerMaterials = {
    X: [matRed, matRed],
    Y: [matGreen, matGreen],
    Z: [matBlue, matBlue],
  }
  const handlersMesh = ref<Mesh[]>([])
  const init = (camera: Camera, domElement: HTMLElement) => {
    catchCamera.value = camera
    catchElement.value = domElement
    return root.value
  }

  const initDragHandler = () => {
    for (const i in handlers.value) {
      handlers.value[i].forEach((element, index) => {
        const mesh = new Mesh(
          new BoxGeometry(1, 1, 1),
          handlerMaterials[i][index],
        )
        const positionX = handlers.value[i][index].x
        const positionY = handlers.value[i][index].y
        const positionZ = handlers.value[i][index].z
        mesh.position.copy(new Vector3(positionX, positionY, positionZ))
        handlersMesh.value.push(mesh)
        root.value.add(mesh)
      })
    }
  }
  const attach = (obj: Object3D) => {
    object.value = obj
    initDragHandler()
  }

  const getRoot = () => {
    return root.value
  }

  return {
    init,
    attach,
    getRoot,
  }
}
